/* Copyright 2001,2002,2003 NAH6
 * All Rights Reserved
 *
 * Parts Copyright DoD, Parts Copyright Starium
 *
 */
#include "main.h"
#include "StochCB.h"
#include "conv_cor.h"
#include "scb_code.h"
#include "stoch.h"


static void CalcStochGain(
float	LPCImpResp[SF_LEN],
float	Residual[RES_LEN],
int	*cbindex,
float	*StochGain,
int	*codeword);

/**************************************************************************
*                                                                         *
* ROUTINE
*		StochasticAnalysis
*
* FUNCTION
*               Find optimal MSPE excitation code word
* SYNOPSIS
*		StochasticAnalysis(scale, LPCImpResp, Residual, 
*			StochasticIndex, StochasticGain, OptExc)
*
*   formal
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*	scale		float	 i	Mixed excitation scaling factor
*	LPCImpResp	float	 i	LPC Impulse response
*	Residual	float	 i	Residual from adaptive analysis
*	StochasticIndex	int	 o	Stochastic codebook index
*	StochasticGain	int	 o	Stochastic codebook gain
*	OptExc		float	 o	Optimum excitation vector
*
**************************************************************************
*	
* DESCRIPTION
*
*  Code book search is performed by closed-loop analysis using conventional
*  minimum squared prediction error (MSPE) criteria of the perceptually
*  weighted error signal.  The code book is overlaped to allow recursive
*  computational savings in routine ConvCor:
*
*	index	code book
*		+-----------------------+
*	1	| 2M-1         2(M-1)+L |
*	2	| 2(M-2)+1     2(M-2)+L |
*	:	| :            :	|
*	N-1	| .            .	|
*	N	| .            .	|
*	:	| 3            62	|
*	:	| 1            60	|
*		+-----------------------+
*
*	where: M = maximum code book size
*	       N = actual code book search size (any value between 1 & M)
*	       L = code word length
*
*	each code word is:  2(M-index)+1 -> 2(M-index)+L
*  	
***************************************************************************/
void StochasticAnalysis(
float	scale,
float	LPCImpResp[SF_LEN],
float	Residual[RES_LEN],
int	*StochasticIndex,
float	*StochasticGain,
float	OptExc[SF_LEN])
{
int	i;
int	gindex;
int	codeword;

/*  Calculate gain for each codeword, search for best codeword */
	CalcStochGain(LPCImpResp, Residual, StochasticIndex, StochasticGain,
		&codeword);

/*  Apply constrained excitation factor */
	*StochasticGain *= scale;

/*  Quantize gain */
	*StochasticGain = SCBGainEncode(*StochasticGain, &gindex);

/*  Scale selected code word vector into excitation array */
	for(i=0; i<SF_LEN; i++)
	  OptExc[i] = *StochasticGain*StochCB[i+codeword];
	
}
/*

*************************************************************************
*                                                                         *
* ROUTINE
*		CalcStochGain
*
* FUNCTION
*               Find gain and -error term for each codeword
*		and search for best code word (max -error term)
*		(codewords are overlapped by shifts of -2
*		along the code vector x)
*		NOTE:  gain[i] and err[i] are replaced by scalars
* SYNOPSIS
*		CalcStochGain(LPCImpResp, Residual, cbindex, gain, codeword)
*
*   formal
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*	LPCImpResp	float	 i	LPC Impulse Response
*	Residual	float	 i	Residual after adaptive analysis
*	cbindex		int	 o	Pointer to best codeword
*	StochGain	int	 o	Best gain
*	codeword	int	 o	Best codeword
*
**************************************************************************/

#define LEN_TRUNC_H	30

void CalcStochGain(
float	LPCImpResp[SF_LEN],
float	Residual[RES_LEN],
int	*cbindex,
float	*StochGain,
int	*codeword)
{
float	emax, err;
int 	i;
float	gain;

/*  Initialize */
	*codeword = 2*MAX_STOCH_CB_SIZE-2;
	*cbindex = 1;
	*StochGain = ConvCor(&StochCB[*codeword], SF_LEN, TRUE, LPCImpResp, 
		LEN_TRUNC_H, Residual, &err);
	emax = err;
	*codeword -= 2;

/*  Calculate gain and error */
	for(i=1; i< STOCH_CB_SIZE; i++)	{
	  gain = ConvCor(&StochCB[*codeword], SF_LEN, FALSE, LPCImpResp,  
		LEN_TRUNC_H, Residual, &err);
	  *codeword -= 2;
	  if(err >= emax)	{
	    emax = err;
	    *cbindex = i+1;
	    *StochGain = gain;
	  }
	}

/*  Calculate pointer to best code word */
	*codeword = 2*(MAX_STOCH_CB_SIZE - *cbindex);

}
